#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/device.h>
#include <linux/device/class.h>
#include <linux/delay.h>
#include <linux/fs.h>

#include "light_drv.h"

struct i2c_client *client;
struct class *pCls;
int major;

int sensor_init(void)
{
    int ret;
    // 复位
    char buf[] = {0, 4};
    struct i2c_msg msg[] = {
        {
            .addr = client->addr,
            .flags = 0,
            .len = 2,
            .buf = buf,
        }};
    ret = i2c_transfer(client->adapter, msg, 1);
    if (ret != 1)
    {
        printk(KERN_ERR "i2c_transfer failed(1)\n");
        return -1;
    }
    printk(KERN_INFO "i2c_transfer success(1)\n");
    msleep(10);
    // 设置测光照模式
    msg[0].buf[0] = 0;
    msg[0].buf[1] = 1;
    ret = i2c_transfer(client->adapter, msg, 1);
    if (ret != 1)
    {
        printk(KERN_ERR "i2c_transfer failed(2)\n");
        return -1;
    }
    printk(KERN_INFO "i2c_transfer success(2)\n");
    msleep(100);
    return 0;
}

int get_value(void)
{
    int ret, i;
    // 复位
    char buf[] = {0x0C, 0x0D};
    struct i2c_msg msg[] = {
        {
            .addr = client->addr,
            .flags = 0,
            .len = 2,
            .buf = buf,
        }};
    // 写，读数据的寄存器地址
    ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    if (ret != ARRAY_SIZE(msg))
    {
        printk(KERN_ERR "i2c_transfer failed(3)\n");
        return -1;
    }
    printk(KERN_INFO "i2c_transfer success(3)\n");
    // 读数据
    msg[0].buf[0] = 0x00;
    msg[0].buf[1] = 0x00;
    msg[0].flags = 1;
    msg[0].buf = buf;
    ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    if (ret != ARRAY_SIZE(msg))
    {
        printk(KERN_ERR "i2c_transfer failed(4)\n");
        return -1;
    }
    printk(KERN_INFO "i2c_transfer success(4)\n");

    for (i = 0; i < 2; i++)
    {
        printk(KERN_INFO "buf[%d] = %#X\n", i, buf[i]);
    }
    return (buf[1] << 8) | buf[0];
}

long file_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    int value;
    if (cmd == LIGHT_GET)
    {
        value = get_value();
        copy_to_user((int *)arg, &value, sizeof(int));
        return 0;
    }
    return 0;
}

struct file_operations fops = {
    .unlocked_ioctl = file_ioctl,
};

int light_probe(struct i2c_client *client_p, const struct i2c_device_id *id)
{
    struct device *pDev;
    printk(KERN_INFO "light_probe\n");
    client = client_p;
    //
    sensor_init();
    //
    major = register_chrdev(0, "mylight", &fops);
    if (major < 0)
    {
        printk(KERN_ERR "register_chrdev failed\n");
        return -1;
    }
    printk(KERN_INFO "register_chrdev succedss! major = %d\n", major);
    //
    pCls = class_create(THIS_MODULE, "mylight");
    if (IS_ERR(pCls))
    {
        printk(KERN_ERR "class_create failed\n");
        unregister_chrdev(major, "mylight");
        return -1;
    }
    printk(KERN_INFO "class_create success\n");
    //
    pDev = device_create(pCls, NULL, MKDEV(major, 0), NULL, "mylight");
    if (IS_ERR(pDev))
    {
        printk(KERN_ERR "device_create failed\n");
        class_destroy(pCls);
        unregister_chrdev(major, "mylight");
        return -1;
    }
    printk(KERN_INFO "device_create success\n");
    //

    return 0;
}

int light_remove(struct i2c_client *client)
{
    printk(KERN_INFO "light_remove\n");
    return 0;
}

struct of_device_id match_table[] = {
    {.compatible = "zr,mylight"},
    {}};

struct i2c_driver light_drv = {
    .driver = {
        .name = "mylight",
        .of_match_table = match_table,
    },
    .probe = light_probe,
    .remove = light_remove,
};

module_i2c_driver(light_drv);
MODULE_LICENSE("GPL");